﻿using System;
using Microsoft.Practices.Prism.Modularity;

namespace UltimateNavigationFramework.Loaders
{
    public class UltimateModuleLoadingService : IUltimateModuleLoadingService
    {
        #region Private members
        private IModuleManager _moduleManager;
        private IUltimateModuleRegistrationService _moduleRegistrationService; 
        #endregion

        #region Module Download State Changed
        public EventHandler<UltimateModuleDownloadProgressChangedEventArgs> ModuleDownloadStateChanged
        {
            get;
            set;
        } 
        #endregion

        #region Constructor
        public UltimateModuleLoadingService(IModuleManager moduleManager, IUltimateModuleRegistrationService moduleRegistrationService)
        {
            this._moduleManager = moduleManager;
            this._moduleRegistrationService = moduleRegistrationService;
            this._moduleManager.ModuleDownloadProgressChanged += _moduleManager_ModuleDownloadProgressChanged;
            this._moduleManager.LoadModuleCompleted += _moduleManager_LoadModuleCompleted;
        } 
        #endregion

        #region Load Module
        public void LoadModule(string moduleName, Action<bool, Exception> completeCallback)
        {
            if (!string.IsNullOrEmpty(moduleName))
            {
                var realModule =
                    this._moduleRegistrationService.GetRealModuleInfo(moduleName);

                if (!this._moduleRegistrationService.ModuleIsLoaded(moduleName))
                {                    
                    this._moduleManager.LoadModule(realModule.ModuleName);
                    
                    EventHandler<LoadModuleCompletedEventArgs> handler = null;

                    handler = (s, e) =>
                    {
                        if (moduleName == e.ModuleInfo.ModuleName)
                        {
                            this._moduleManager.LoadModuleCompleted -= handler;
                            completeCallback(e.Error == null, e.Error);
                        }
                    };

                    this._moduleManager.LoadModuleCompleted += handler;
                }
                else
                    completeCallback(true, null);
            }
        } 
        #endregion

        #region Private Events
        void _moduleManager_ModuleDownloadProgressChanged(object sender, ModuleDownloadProgressChangedEventArgs e)
        {
            this.InvokeModuleStateChange(UltimateModuleDownloadStatus.Downloading, e.ModuleInfo.ModuleName, e.ProgressPercentage);
        }

        void _moduleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
        {
            this.InvokeModuleStateChange(UltimateModuleDownloadStatus.Downloaded, e.ModuleInfo.ModuleName, 100, e.Error);

            if (e.Error == null && e.ModuleInfo.State == ModuleState.Initialized)
                this.InvokeModuleStateChange(UltimateModuleDownloadStatus.Initialized, e.ModuleInfo.ModuleName, 100);
        }

        void InvokeModuleStateChange(UltimateModuleDownloadStatus status,
                                        string moduleName,
                                        double percentage,
                                        Exception exception = null)
        {
            if (this.ModuleDownloadStateChanged != null)
                this.ModuleDownloadStateChanged(this, new UltimateModuleDownloadProgressChangedEventArgs()
                {
                    Error = exception,
                    ModuleDownloadStatus = status,
                    ModuleName = moduleName,
                    Percentage = percentage
                });
        } 
        #endregion
    }
}
